#!/usr/bin/perl

######################################################################
package Swignition::uF::hFreebusy;
######################################################################

use CGI::Util;
use Swignition::GenericParser::Utils;
use Swignition::MagicInterval;
use Swignition::uF;
use XML::LibXML qw(:all);
use strict;

sub cc
{
	$_ = shift;
	s/\-([a-z])/uc($1)/eg;
	return $_;
}

sub parse_all
{
	my $page   = shift;
	my $within = shift || $page->{DOM};
	my @nodes  = searchClass('vfreebusy', $within);
	my @rv;
	
	foreach my $ev (@nodes)
	{
		push @rv, parse($page, $ev);
	}
	
	return @rv;
} #/sub parse_all


sub uri
{
	my $this = shift;
	my $all  = shift;
	my @rv;
	
	if (length $this->{_id})
	{
		push @rv, Swignition::uF::TDBURI($this->{_page}->uri.'#'.$this->{_id});
	}
	if (lc($this->{_dom}->tagName) eq 'body')
	{
		push @rv, Swignition::uF::TDBURI($this->{_page}->uri);
	}
	if (length $this->{uid})
	{
		push @rv, UIDURI($this, 'cal');
	}
	push @rv, Swignition::GenericParser::Utils::BNodeURI($this->{_dom}, 'FreeBusy')
		unless (@rv);
	
	return $rv[0] unless (defined $all);
	while ($all) { shift @rv; $all--; }
	return @rv;
} #/sub uri


sub rdf_subject
{
	my $this    = shift;
	my $ns      = 'http://www.w3.org/2002/12/cal/ical#';

	# Create RDF subject
	my $subject = Swignition::RDFModel::Subject->new($this->uri);
	$subject->addObject($this);
	$subject->setDom($this->{_dom});
	
	$subject->addVal('http://www.w3.org/1999/02/22-rdf-syntax-ns#type',
		Swignition::RDFModel::Value->new($ns.'Vfreebusy', 1));
	
	# Patterns for simple data.
	my @_SINGLES  = qw(summary comment dtstart dtend duration dtstamp uid);
	my @_SINGLESR = qw(parent);
	my @_MULTIS   = qw();
	my @_MULTISR  = qw(url child sibling);
	my @_OBJECTS  = qw(freebusy contact attendee organizer);
	
	# Properties which exist as singles.
	foreach my $property (@_SINGLES)
	{
		next unless (length $this->{$property});
		my $val = Swignition::RDFModel::Value->new($this->{$property});
		$subject->addVal($ns.$property, $val);
	}

	# Resource-type properties which exist as singles.
	foreach my $property (@_SINGLESR)
	{
		next unless (length $this->{$property});
		my $val = Swignition::RDFModel::Value->new($this->{$property}, 1);
		if ($property eq 'parent')
			{ $subject->addVal('http://buzzword.org.uk/rdf/icalx#'.$property, $val); }
		else
			{ $subject->addVal($ns.cc($property), $val); }
	}
		
	# Properties which exist as multiple values.
	foreach my $property (@_MULTIS)
	{
		foreach my $V (@{ $this->{$property} })
		{
			next unless (length $V);
			my $val = Swignition::RDFModel::Value->new($V);
			$subject->addVal($ns.$property, $val);
		}
	}
	
	# Resource-type properties which exist as multiple values.
	foreach my $property (@_MULTISR)
	{
		foreach my $V (@{ $this->{$property} })
		{
			next unless (length $V);
			my $val = Swignition::RDFModel::Value->new($V, 1);
			if ($property eq 'child' || $property eq 'sibling')
				{ $subject->addVal('http://buzzword.org.uk/rdf/icalx#'.$property, $val); }
			else
				{ $subject->addVal($ns.cc($property), $val); }
		}
	}

	# Embedded objects which may be represented as resources
	foreach my $property (@_OBJECTS)
	{
		foreach my $V (@{ $this->{$property} })
		{
			my $val;
			if (ref $V)
				{ $val = Swignition::RDFModel::Value->new($V->uri, 1); }
			else
				{ $val = Swignition::RDFModel::Value->new($V); }
			$subject->addVal($ns.$property, $val);
		}
	}
	
	return $subject;
	
} #/sub rdf_subject


sub metadata_ns
{
	return {
		'i'  => { nsurl=>'http://www.w3.org/2002/12/cal/ical#',    title=>'RDF Calendar' },
		'ix' => { nsurl=>'http://buzzword.org.uk/rdf/icalx#', title=>'RDF Calendar (Extentions)' }
		};
} #/sub metadata_ns


sub parse
{
	my $page = shift;
	my $rv = { '_dom'=>shift };
	my $pkg = __PACKAGE__;
	if (defined $page->{uF}->{_Shortcuts}->{$pkg}->{ $rv->{_dom}->getAttribute('_xpath') })
		{ return $page->{uF}->{_Shortcuts}->{$pkg}->{ $rv->{_dom}->getAttribute('_xpath') }; }
	else
		{ $page->{uF}->{_Shortcuts}->{$pkg}->{ $rv->{_dom}->getAttribute('_xpath') } = $rv; }
	
	my $event_node = $rv->{'_dom'}->cloneNode(1);
	
	my $id = $event_node->getAttribute('id');
	$rv->{_id} = $id if (length $id);
	$rv->{_page} = $page;
	
	data_patterns($page, $event_node, 4);
	
	simple_parse(
		$rv,
		$event_node,
		[
			['organizer',   'M*',  {'embedded'=>'hCard !person','is-in-cal'=>1}],
			['attendee',    'M*',  {'embedded'=>'hCard !person','is-in-cal'=>1}],
			['contact',     'M*',  {'embedded'=>'hCard !person','is-in-cal'=>1}],
			['comment',     '?'],
			['dtstart',     'd1'],
			['dtend',       'd?'],
			['dtstamp',     'd?'],
			['duration',    'D?'],
			['summary',     '1'],
			['uid',         'U?'],
			['url',         'U?'],
		]
	);

	# Freebusy itself - too tricky for simple_parse();
	my @nodes = searchClass('freebusy', $event_node);
	foreach my $n (@nodes)
	{
		my @accumValue;
		my @accumType;
		
		foreach my $v (searchClass('value', $n))
		{
			push @accumValue, Swignition::MagicInterval->parse(STRINGIFY($v, undef, 1), $v, $page);
			$v->getParentNode->removeChild($v);
		}
		
		my $type;
		my @nodes = searchClass('fbtype', $n);
		$type = uc(STRINGIFY($nodes[0], undef, 1)) if (@nodes);
		
		my $C = {
				'value'  => \@accumValue,
				'fbtype' => $type,
				'_id'    => $n->getAttribute('id'),
				'_xp'    => Swignition::GenericParser::Utils::XPointer($n, $page->uri),
				'_page'  => $page,
				'_component' => $rv,
				'_dom'   => $n
			};
		bless $C, "Swignition::uF::hFreebusy::fb";
		push @{ $rv->{freebusy} }, $C;
	}
	
	bless $rv;
	Swignition::uF::error_list_process($rv, $page, 'http://microformats.org/wiki/User:TobyInk/hcalendar-1.1');
	return $rv;
	
} #/sub parse


1; #/package Swignition::uF::hFreebusy






######################################################################
package Swignition::uF::hFreebusy::fb;
######################################################################

sub uri
{
	my $this = shift;
	my $all  = shift;
	my @rv;

	if (length $this->{_id})
	{
		push @rv, Swignition::uF::TDBURI($this->{_page}->uri.'#'.$this->{_id});
	}
	push @rv, Swignition::GenericParser::Utils::BNodeURI($this->{_dom}, 'FBInfo');
	
	return $rv[0] unless (defined $all);
	while ($all) { shift @rv; $all--; }
	return @rv;
} #/sub uri

sub rdf_subject
{
	my $this    = shift;

	# Create RDF subject
	my $subject = Swignition::RDFModel::Subject->new($this->uri);
	$subject->addObject($this);
	$subject->setDom($this->{_dom});
	
	$subject->addVal('http://www.w3.org/1999/02/22-rdf-syntax-ns#type',
		Swignition::RDFModel::Value->new('http://buzzword.org.uk/rdf/icalx#Freebusy', 1));
	
	if (length $this->{'fbtype'})
	{
		my $val = Swignition::RDFModel::Value->new($this->{'fbtype'});
		$subject->addVal('http://buzzword.org.uk/rdf/icalx#fbtype', $val);
	}

	foreach my $V (@{ $this->{'value'} })
	{
		next unless (length $V);
		my $val = Swignition::RDFModel::Value->new($V);
		$subject->addVal('http://www.w3.org/1999/02/22-rdf-syntax-ns#value', $val);
	}
	
	return $subject;
	
} #/sub rdf_subject

1; #/package Swignition::uF::hFreebusy::fb
